home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-02-27 | 12.3 KB | 445 lines | [TEXT/PJMM] |
- { MovableModal: This unit implements a MovableModalDialog routine similar to the Toolbox routine ModalDialog }
- { to be used for movable modal dialogs }
- {}
- { ANTIĀ© 1993 Merzwaren, modified by Sebastiano Pilla 1996 }
-
- { <mailto:case@tvol.it> }
-
- unit MovableModal;
-
-
- interface
-
-
- uses
- Dialogs;
-
-
- procedure DisableMenuBar (inEditMenuID: SInt16;
- inHmnuID: SInt16);
-
- procedure ReEnableMenuBar;
-
- procedure MovableModalDialog (inFilterUPP: ModalFilterUPP;
- var ioItemHit: SInt16);
-
-
- implementation
-
-
- uses
- Balloons, LowMem;
-
-
- const
- kSystemMenuThreshold = -16000; { menu IDs <= than this are used by the system }
- kMovableModalEventMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask;
- kCutKeyEquiv = 'X';
- kCopyKeyEquiv = 'C';
- kPasteKeyEquiv = 'V';
-
-
- type
- MenuEntry = record
- hMenu: MenuHandle;
- leftEdge: SInt16;
- end;
-
-
- MenuList = record
- offsetToLastMenu: SInt16;
- rightmostEdge: SInt16;
- unused: SInt16;
- theMenus: array[0..100] of MenuEntry;
- end;
- MenuListPtr = ^MenuList;
- MenuListH = ^MenuListPtr;
-
-
- MenuBarState = record
- mbsBarEnable: UInt32;
- mbsEditEnable: UInt32;
- mbsEditMenuID: SInt16;
- mbsCutItem: SInt16;
- mbsCopyItem: SInt16;
- mbsPasteItem: SInt16;
- end;
- MenuBarStatePtr = ^MenuBarState;
- MenuBarStateH = ^MenuBarStatePtr;
-
-
- var
- pSaveStateHdl: Handle;
-
-
- { GetMenuItemFromKeyEquiv }
- {}
- { Returns the item number of the menu item with the given char }
- {}
- { Entry: inMenu = handle to menu }
- { inKeyEquiv = key equivalent }
- { Exit: function result = item number requested }
- function GetMenuItemFromKeyEquiv (inMenu: MenuHandle;
- inKeyEquiv: Char): SInt16;
- var
- item, nItems: SInt16;
- cmd: Char;
- begin
- GetMenuItemFromKeyEquiv := 0;
- nItems := CountMItems(inMenu);
- for item := 1 to nItems do
- begin
- GetItemCmd(inMenu, item, cmd);
- if (Ord(cmd) = Ord(inKeyEquiv)) then
- begin
- GetMenuItemFromKeyEquiv := item;
- Exit(GetMenuItemFromKeyEquiv);
- end;
- end;
- end;
-
-
- { DisableMenuBar }
- {}
- { Disables the entire menu bar, excluding the Edit & System menus }
- {}
- { Entry: inEditMenuID = resource ID of Edit menu (or 0 if no Edit menu) }
- { inHmnuID = resource ID of valid 'hmnu' resource (or -1 if no string remapping desired) }
- { Note: Call this routine soon after putting up the movable modal, so the frontmost window is assured }
- { to be the dialog }
- procedure DisableMenuBar (inEditMenuID: SInt16;
- inHmnuID: SInt16);
- var
- menuList: MenuListH;
- theMenu: MenuHandle;
- menuEnable: UInt32;
- theDialog: DialogPtr;
- barEnable, response: SInt32;
- i, nMenus, menuID: SInt16;
- err: OSErr;
- hasBalloons, needEditMenu: Boolean;
- begin
- hasBalloons := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & BTST(response, gestaltHelpMgrPresent);
-
- { determine if the frontmost dialog contains edit fields }
- theDialog := FrontWindow;
- needEditMenu := (theDialog <> nil) & (DialogPeek(theDialog)^.editField >= 0);
-
- { get a handle to the menu list and count the menus }
- menuList := MenuListH(LMGetMenuList);
- nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
-
- { create a parameter block for saving menu bar state information }
- pSaveStateHdl := NewHandleClear(SizeOf(MenuBarState));
- if pSaveStateHdl <> nil then
- HLock(pSaveStateHdl);
- if MemError = noErr then
- with MenuBarStateH(pSaveStateHdl)^^ do
- begin
- barEnable := 0;
-
- { walk the menu list }
- for i := 0 to nMenus - 1 do
- begin
-
- { get menu handle, menu ID and enable flags for this menu }
- theMenu := menuList^^.theMenus[i].hMenu;
- menuID := theMenu^^.menuID;
- menuEnable := theMenu^^.enableFlags;
-
- { do nothing if this is a system menu }
- if (menuID <= kSystemMenuThreshold) then
- Cycle;
-
- { if this is the Edit menu and we need it, do some special processing }
- if ((needEditMenu) and (menuID = inEditMenuID)) then
- begin
-
- { save edit menu ID }
- mbsEditMenuID := inEditMenuID;
-
- { save the enable flags for later restoration }
- mbsEditEnable := menuEnable;
-
- { find which items are Cut, Copy and Paste }
- mbsCutItem := GetMenuItemFromKeyEquiv(theMenu, kCutKeyEquiv);
- mbsCopyItem := GetMenuItemFromKeyEquiv(theMenu, kCopyKeyEquiv);
- mbsPasteItem := GetMenuItemFromKeyEquiv(theMenu, kPasteKeyEquiv);
-
- { enable Cut, Copy and Paste }
- menuEnable := 1 + BSL(1, mbsCutItem) + BSL(1, mbsCopyItem) + BSL(1, mbsPasteItem);
- theMenu^^.enableFlags := menuEnable;
-
- Cycle;
- end;
-
- { if this menu is enabled, disable it and set the corresponding bit in barEnable }
- if (BTST(menuEnable, 0)) then
- begin
- barEnable := BOR(barEnable, BSL(1, i));
- DisableItem(theMenu, 0);
- end;
-
- { remap the help strings for this menu }
- if (hasBalloons) then
- err := HMSetMenuResID(menuID, inHmnuID);
- end;
- mbsBarEnable := barEnable;
- end;
-
- { unhighlight the highlighted menu (if any) and redraw the menu bar }
- HiliteMenu(0);
- DrawMenuBar;
-
- { unlock state info parameter block }
- HUnlock(pSaveStateHdl);
- end;
-
-
- { ReEnableMenuBar }
- {}
- { Restores the previously saved enableFlags for all menus in the menu bar }
- {}
- { Note: Call this routine just after bringing down the movable modal }
- procedure ReEnableMenuBar;
- var
- menuList: MenuListH;
- response: SInt32;
- theMenu: MenuHandle;
- i, nMenus, menuID: SInt16;
- hasBalloons: Boolean;
- err: OSErr;
- begin
- { sanity check: make sure pSaveStateHdl isn't NIL }
- if (pSaveStateHdl = nil) then
- Exit(ReEnableMenuBar);
-
- { determine if the Help manager is available }
- hasBalloons := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & BTST(response, gestaltHelpMgrPresent);
-
- { get a handle to the menu list and count the menus }
- menuList := MenuListH(LMGetMenuList);
- nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
-
- HLock(pSaveStateHdl);
- if MemError = noErr then
- with MenuBarStateH(pSaveStateHdl)^^ do
- begin
-
- { walk the menu list }
- for i := 0 to nMenus - 1 do
- begin
-
- { get menu handle and menu ID for this menu }
- theMenu := menuList^^.theMenus[i].hMenu;
- menuID := theMenu^^.menuID;
-
- { do nothing if this is a system menu }
- if (menuID <= kSystemMenuThreshold) then
- Cycle;
-
- { restore old enable state for this menu }
- if (menuID = mbsEditMenuID) then
- theMenu^^.enableFlags := mbsEditEnable
- else if (BTST(mbsBarEnable, i)) then
- EnableItem(theMenu, 0);
-
- { unmap the help strings for this menu }
- if (hasBalloons) then
- err := HMSetMenuResID(menuID, -1);
- end;
- end;
-
- { forget about the menu bar parameter block }
- HUnlock(pSaveStateHdl);
- if pSaveStateHdl <> nil then
- DisposeHandle(pSaveStateHdl);
-
- { redraw the menu bar }
- DrawMenuBar;
- end;
-
-
- { CallBeeper }
- {}
- { Calls the beeper procedure with the given sound }
- {}
- { Entry: soundNo = ID of 'snd ' resource to play }
- { beeperProc = pointer to beeper proc }
- procedure CallBeeper (soundNo: SInt16;
- beeperProc: ProcPtr);
- inline
- $205F, { movea.l (sp)+, a0 }
- $4E90; { jsr (a0) }
-
-
- { MovableModalMenuChoice }
- {}
- { Called by the filter proc to process menu choices }
- {}
- { Entry: inDialog = pointer to current dialog }
- { inEvent = ignored }
- { inMenuChoice = menu choice combination }
- { Exit: outItemHit = item number of edit field interested }
- { function result = TRUE if edit operation performed, FALSE otherwise }
- function MovableModalMenuChoice (inDialog: DialogPtr;
- var inEvent: EventRecord;
- var outItemHit: SInt16;
- inMenuChoice: SInt32): Boolean;
- var
- itemRect: Rect;
- itemHandle: Handle;
- menuID, menuItem, currentEditField, itemType: SInt16;
- err: OSErr;
- begin
- MovableModalMenuChoice := false;
- if (pSaveStateHdl = nil) then
- Exit(MovableModalMenuChoice);
- menuID := HiWrd(inMenuChoice);
- menuItem := LoWrd(inMenuChoice);
- HLock(pSaveStateHdl);
- if MemError = noErr then
- with MenuBarStateH(pSaveStateHdl)^^ do
- begin
- if (menuID = mbsEditMenuID) then
- begin
-
- { find the current edit field }
- currentEditField := DialogPeek(inDialog)^.editField + 1;
- GetDialogItem(inDialog, currentEditField, itemType, itemHandle, itemRect);
-
- { if the current edit field is an enabled item, exit from MovableModalDialog loop }
- if (BAND(itemType, kItemDisableBit) = 0) then
- begin
- MovableModalMenuChoice := true;
- outItemHit := currentEditField;
- end;
-
- { perform edit operation }
- if (menuItem = mbsCutItem) then
- begin
- DialogCut(inDialog);
- err := ZeroScrap;
- err := TEToScrap;
- end
- else if (menuItem = mbsCopyItem) then
- begin
- DialogCopy(inDialog);
- err := ZeroScrap;
- err := TEToScrap;
- end
- else if (menuItem = mbsPasteItem) then
- DialogPaste(inDialog);
- end;
- end;
- HUnlock(pSaveStateHdl);
- HiliteMenu(0);
- end;
-
-
- { HandleMovableModalMouseDown }
- {}
- { Handles mouse down events for the filter proc }
- {}
- { Entry: inDialog = pointer to dialog }
- { ioEvent = event specification }
- { ioItemHit = item number of dialog item interested }
- { Exit: ioEvent = event spec after executing }
- { ioItemHit = item number of edit field interested }
- { function result = TRUE if the filter proc should exit, FALSE otherwise }
- function HandleMovableModalMouseDown (inDialog: DialogPtr;
- var ioEvent: EventRecord;
- var ioItemHit: SInt16): Boolean;
- var
- dragRect: Rect;
- wind: WindowPtr;
- beeper: UniversalProcPtr;
- partCode: SInt16;
- begin
- HandleMovableModalMouseDown := false;
-
- { find out where the click went down in }
- partCode := FindWindow(ioEvent.where, wind);
-
- { if the click went in the menu bar, just call MenuSelect }
- if (partCode = inMenuBar) then
- begin
- HandleMovableModalMouseDown := MovableModalMenuChoice(inDialog, ioEvent, ioItemHit, MenuSelect(ioEvent.where));
- Exit(HandleMovableModalMouseDown);
- end;
-
- { if the user clicked somewhere outside the dialog but in one of our windows behind, call the beeper }
- if not ((partCode = inDesk) or (partCode = inSysWindow)) then
- if (not PtInRgn(ioEvent.where, WindowPeek(inDialog)^.strucRgn)) then
- begin
- beeper := LMGetDABeeper;
- if (beeper <> nil) then
- CallBeeper(1, beeper);
- Exit(HandleMovableModalMouseDown);
- end;
-
- { now, we have to handle the only thing DialogSelect doesn't do for us: dragging }
- if (partCode = inDrag) & (inDialog = wind) then
- begin
- dragRect := GetGrayRgn^^.rgnBBox;
- DragWindow(wind, ioEvent.where, dragRect);
- ioEvent.what := nullEvent;
- end;
- end;
-
-
- { MovableModalDialog }
- {}
- { Substitutes ModalDialog for movable modal dialogs }
- {}
- { Entry: inFilterUPP = same as modalFilter parameter for ModalDialog }
- { ioItemHit = same as itemHit parameter for ModalDialog }
- { Exit: ioItemHit = same as itemHit parameter for ModalDialog }
- procedure MovableModalDialog (inFilterUPP: ModalFilterUPP;
- var ioItemHit: SInt16);
- var
- theEvent: EventRecord;
- savePort: GrafPtr;
- theDialog: DialogPtr;
- gotEvent: Boolean;
- begin
- ioItemHit := 0;
-
- { get a pointer to the frontmost window (which should be our movable dialog) }
- theDialog := FrontWindow;
- if (theDialog = nil) then
- Exit(MovableModalDialog);
-
- { set thePort to the dialog }
- GetPort(savePort);
- SetPort(theDialog);
-
- { modal dialog event loop }
- repeat
-
- { yield time to other processes and retrieve next event from the queue }
- gotEvent := WaitNextEvent(kMovableModalEventMask, theEvent, GetCaretTime, nil);
-
- { the filter proc is the first one to get a chance to process the event }
- if (inFilterUPP <> nil) & CallModalFilterProc(theDialog, theEvent, ioItemHit, inFilterUPP) then
- Leave;
-
- { then comes our own processing of clicks in the menu bar and in the drag bar }
- if (theEvent.what = mouseDown) & HandleMovableModalMouseDown(theDialog, theEvent, ioItemHit) then
- Leave;
-
- { and our processing of keyboard equivalents for the Edit items }
- if (theEvent.what = keyDown) & (BAND(theEvent.modifiers, cmdKey) <> 0) & MovableModalMenuChoice(theDialog, theEvent, ioItemHit, MenuKey(CHR(BAND(theEvent.message, charCodeMask)))) then
- Leave;
-
- { finally we let the Toolbox do its own thing }
- if IsDialogEvent(theEvent) & DialogSelect(theEvent, theDialog, ioItemHit) then
- Leave;
- until false;
-
- { restore the old port }
- SetPort(savePort);
- end;
-
-
- end.